package com.xtt._01_java8.FunctionalInterface;

import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.*;

/**
 * @Author xtt.
 * @Description:
 * @Date:Create in 2017/9/11 0011 下午 22:24
 * @Modify By:
 */
public class TestFunctionInterface {

    public static String toUpperCase(String str) {
        return str.toUpperCase();
    }

    @Test
    public void testOld() throws Exception {

        Runnable run1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("run");
            }
        };
        run1.run();

        Runnable runnable = () -> System.out.println("run");
        runnable.run();

        Callable<String> call1 = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "testCall";
            }
        };
        System.out.println(call1.call());

        Callable<String> call2 = () -> "testCallable";
        System.out.println(call2.call());

    }

    @Test
    public void testFun() {
        //Supplier:代表一个输出
        Supplier<String> sup = () -> "hello";
        System.out.println(sup.get());

        Supplier<String> sup2 = () -> {return "hello";};
        System.out.println(sup2.get());

        //Supplier:代表一个输出
        Consumer<String> con = (str) -> System.out.println(str);
        con.accept("hello");

        //Consumer:代表一个输入
        BiConsumer<Integer,Integer> con2 = (a,b) -> System.out.println(a+b);
        con2.accept(1,3);

        //BiConsumer:代表两个输入
        BiConsumer<Integer,Integer> con3 = (a,b) -> {System.out.println(a+b);};
        con3.accept(1,3);

        //Function :代表一个输出一个输入(输入和输出一般不一样)
        Function<Integer,Integer> fn = (a) -> a+98;
        System.out.println(fn.apply(1));

        //UnaryOperator:一个输入一个输出(输入输出相同类型)
        UnaryOperator<Integer> uo = (a) -> a+99;
        System.out.println(uo.apply(1));

        //BiFunction:两个输入，一个输出
        BiFunction<Integer,Integer,Integer> bfn = (a,b) -> a+b;
        System.out.println(bfn.apply(50,50));

        //BinaryOperator:两个输入，一个输出(输入输出相同类型)
        BinaryOperator<Integer> bo = (a,b) -> a+b;
        System.out.println(bo.apply(50,51));

    }

    @Test
    public void testNew() {
        UserMapper<String,Integer> um = (str) -> Integer.parseInt(str);
        System.out.println(um.accept("34"));
    }

    //方法的引用 静态方法
    @Test
    public void testStaticMethod() {
        Consumer<String> con = (str) -> System.out.println(str);
        con.accept("abc");
        Consumer<String> con2 = System.out::println;
        con2.accept("abc");

        Function<String,String> fn = (str) -> TestFunctionInterface.toUpperCase(str);
        System.out.println(fn.apply("cde"));

        Function<String,String> fn2 = TestFunctionInterface::toUpperCase;
        System.out.println(fn2.apply("cde"));

        UnaryOperator<String> uo = TestFunctionInterface::toUpperCase;
        System.out.println(uo.apply("cde"));
    }

    //方法的引用 实例方法的引用
    @Test
    public void testInstMethod() {
        Function<String,String> fn = str -> new Example().toUpperCase(str);
        System.out.println(fn.apply("test"));

        Function<String,String> fn2 = new Example()::toUpperCase;
        System.out.println(fn2.apply("test"));
    }

    //对象方法的引用 （由参数传入）
    @Test
    public void testInstanceMethod() {
        Function<Example,String> fn = e -> e.sayHello();
        System.out.println(fn.apply(new Example()));

        Function<Example,String> fn2 = Example::sayHello;
        System.out.println(fn.apply(new Example()));

        BiFunction<Example,String,String> fn3= (e,str) -> e.sayThis(str);
        System.out.println(fn3.apply(new Example(),"hey"));

        BiFunction<Example,String,String> fn4 = Example::sayThis;
        System.out.println(fn4.apply(new Example(),"hey"));

    }

    //构造方法的引用
    @Test
    public void testConstructorMethod() {
        Supplier<Example> sup = () -> new Example();
        System.out.println(sup.get());

        Supplier<Example> sup2 = Example::new;
        System.out.println(sup2.get());

        Supplier<List<String>> sup3 = ArrayList::new;

        Supplier<Map<String,String>> sup4 = HashMap::new;

        Supplier<String> sup5 = String::new;
    }

}

@FunctionalInterface
interface UserMapper<T,R> {
    R accept(T r);
}

class Example {

    public Example() {
        System.out.println("new Example");
    }

    public String toUpperCase(String str) {
        return str.toUpperCase();
    }

    public String sayHello() {
        return "hello";
    }

    public String sayThis(String str) {
        return str;
    }

    @Override
    public String toString() {
        return "Example{}";
    }
}
